package cn.yang.infrastructure.persistent.repository;

import cn.bugstack.middleware.db.router.strategy.IDBRouterStrategy;
import cn.yang.domain.award.model.aggregate.GiveOutPricesAggregate;
import cn.yang.domain.award.model.aggregate.UserAwardRecordAggregate;
import cn.yang.domain.award.model.entity.TaskEntity;
import cn.yang.domain.award.model.entity.UserAwardRecordEntity;
import cn.yang.domain.award.model.entity.UserCreditAwardEntity;
import cn.yang.domain.award.model.valobj.AccountStateVO;
import cn.yang.domain.award.repository.IAwardRepository;
import cn.yang.infrastructure.event.EventPublisher;
import cn.yang.infrastructure.persistent.dao.*;
import cn.yang.infrastructure.persistent.po.Task;
import cn.yang.infrastructure.persistent.po.UserAwardRecord;
import cn.yang.infrastructure.persistent.po.UserCreditAccount;
import cn.yang.infrastructure.persistent.po.UserRaffleOrder;
import cn.yang.types.enums.ResponseCode;
import cn.yang.types.exception.AppException;
import com.alibaba.fastjson2.JSON;
import lombok.extern.slf4j.Slf4j;
import org.springframework.dao.DuplicateKeyException;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.support.TransactionTemplate;

import javax.annotation.Resource;

/**
 * @version v1.0
 * @ClassName: cn.yang.infrastructure.persistent.repository
 * @Description: TODO
 * @Author: YJ
 */
@Repository
@Slf4j
public class AwardRepository implements IAwardRepository {
    @Resource
    private ITaskDao taskDao;
    @Resource
    private IAwardDao awardDao;
    @Resource
    private IUserCreditAccountDao userCreditAccountDao;
    @Resource
    private IUserAwardRecordDao userAwardRecordDao;
    @Resource
    private IUserRaffleOrderDao userRaffleOrderDao;

    @Resource
    private IDBRouterStrategy dbRouter;
    @Resource
    private TransactionTemplate transactionTemplate;
    @Resource
    private EventPublisher eventPublisher;

    @Override
    public void saveUserAwardRecord(UserAwardRecordAggregate userAwardRecordAggregate) {
        UserAwardRecordEntity userAwardRecordEntity = userAwardRecordAggregate.getUserAwardRecord();
        TaskEntity taskEntity = userAwardRecordAggregate.getTaskEntity();
        String userId = userAwardRecordEntity.getUserId();
        Long activityId = userAwardRecordEntity.getActivityId();
        Integer awardId = userAwardRecordEntity.getAwardId();

        UserAwardRecord userAwardRecord = UserAwardRecord.builder()
                .userId(userId)
                .activityId(activityId)
                .strategyId(userAwardRecordEntity.getStrategyId())
                .orderId(userAwardRecordEntity.getOrderId())
                .awardId(awardId)
                .awardTitle(userAwardRecordEntity.getAwardTitle())
                .awardTime(userAwardRecordEntity.getAwardTime())
                .awardState(userAwardRecordEntity.getAwardState().getCode())
                .build();

        Task task = Task.builder()
                .userId(userId)
                .topic(taskEntity.getTopic())
                .messageId(taskEntity.getMessageId())
                .message(JSON.toJSONString(taskEntity.getMessage()))
                .state(taskEntity.getTaskState().getCode())
                .build();

        UserRaffleOrder userRaffleOrderReq = UserRaffleOrder.builder()
                .userId(userId)
                .orderId(userAwardRecordEntity.getOrderId())
                .build();
        //进行事务
        try {
            dbRouter.doRouter(userId);
            transactionTemplate.execute(status -> {
                try {
                    // 写入记录
                    userAwardRecordDao.insert(userAwardRecord);
                    // 写入任务
                    taskDao.insert(task);
                    //更新抽奖单状态
                    int count = userRaffleOrderDao.updateUserRaffleOrderStateUsed(userRaffleOrderReq);
                    if (1 != count) {
                        status.setRollbackOnly();
                        log.error("写入中奖记录，用户抽奖单已使用过，不可重复抽奖  userId:{},activityId:{},awardId:{}", userId, activityId, awardId);
                        throw new AppException(ResponseCode.ACTIVITY_ORDER_ERROR.getCode(), ResponseCode.ACTIVITY_ORDER_ERROR.getInfo());
                    }
                    return 1;
                } catch (DuplicateKeyException e) {
                    status.setRollbackOnly();
                    log.error("写入中奖记录，唯一索引冲突 userId:{},activityId:{},awardId:{}",
                            userId, activityId, awardId);
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(), ResponseCode.INDEX_DUP.getInfo());
                }

            });
        } finally {
            dbRouter.clear();
        }
        //TODO:线程池实现
        try {
            //发送消息【在事务外执行，如果失败还有任务补偿】
            eventPublisher.publish(task.getTopic(), task.getMessage());
            //更新数据库记录，task任务表
            taskDao.updateTaskSendMessageCompleted(task);
        } catch (Exception e) {
            log.error("写入中奖记录，发送MQ消息失败 userId:{},activityId:{},awardId:{},task:{}",
                    userId, activityId, awardId, JSON.toJSONString(task));
            taskDao.updateTaskSendMessageFail(task);
        }
    }

    @Override
    public String queryAwardConfig(Integer awardId) {
        return awardDao.queryAwardConfigByAwardId(awardId);
    }

    @Override
    public void saveGiveOutPricesAggregate(GiveOutPricesAggregate giveOutPricesAggregate) {
        String userId = giveOutPricesAggregate.getUserId();
        UserAwardRecordEntity userAwardRecordEntity = giveOutPricesAggregate.getUserAwardRecordEntity();
        UserCreditAwardEntity userCreditAwardEntity = giveOutPricesAggregate.getUserCreditAwardEntity();

        //更新发奖记录
        UserAwardRecord userAwardRecordReq = UserAwardRecord.builder()
                .userId(userAwardRecordEntity.getUserId())
                .orderId(userAwardRecordEntity.getOrderId())
                .awardState(userAwardRecordEntity.getAwardState().getCode())
                .build();

        // 更新用户积分 【首次则插入数据】
        UserCreditAccount userCreditAccountReq = UserCreditAccount.builder()
                .userId(userId)
                .totalAmount(userCreditAwardEntity.getCreditAmount())
                .availableAmount(userCreditAwardEntity.getCreditAmount())
                .accountStatus(AccountStateVO.OPEN.getCode())
                .build();

        //进行事务
        try {
            dbRouter.doRouter(userId);
            transactionTemplate.execute(status -> {
                try {
                    // 更新积分 // 创建积分账户
                    int updateAccountCount = userCreditAccountDao.updateAddAmount(userCreditAccountReq);
                    if (0 == updateAccountCount) {
                        userCreditAccountDao.insert(userCreditAccountReq);
                    }
                    //更新奖品记录
                    int updateAwardCount = userAwardRecordDao.updateAwardRecordCompletedState(userAwardRecordReq);
                    if (0 == updateAwardCount) {
                        status.setRollbackOnly();
                        log.error("写入中奖记录，用户抽奖单已使用过，不可重复抽奖  userId:{},orderId:{}",
                                userId, userAwardRecordEntity.getOrderId());
                        throw new AppException(ResponseCode.ACTIVITY_ORDER_ERROR.getCode(), ResponseCode.ACTIVITY_ORDER_ERROR.getInfo());
                    }
                    return 1;
                } catch (DuplicateKeyException e) {
                    status.setRollbackOnly();
                    log.error("写入中奖记录，唯一索引冲突 userId:{}",
                            userId, e);
                    throw new AppException(ResponseCode.INDEX_DUP.getCode(), ResponseCode.INDEX_DUP.getInfo());
                }

            });
        } finally {
            dbRouter.clear();
        }
    }

    @Override
    public String queryAwardKey(Integer awardId) {
        return awardDao.queryAwardKeyByAwardId(awardId);
    }
}


